﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BFlatCompile.Nodes
{
	internal class ArgMatch : Executable
	{
		public string[] MatchExpressions { get; private set; }
		public Executable[] TrueCode { get; private set; }
		public Executable[] FalseCode { get; private set; }

		private ArgMatch(IList<string> matchExpressions, IList<Executable> trueCode, IList<Executable> falseCode)
		{
			this.MatchExpressions = matchExpressions.ToArray();
			this.TrueCode = trueCode.ToArray();
			this.FalseCode = falseCode == null ? null : falseCode.ToArray();
		}

		public static ArgMatch ParseArgMatch(Tokens tokens)
		{
			tokens.PopExpected("argmatch");
			tokens.PopExpected("(");

			List<string> matchList = new List<string>();
			bool first = true;
			while (true)
			{
				string next = tokens.Peek();
				if (next == ")" || next == null)
				{
					break;
				}
				if (!first)
				{
					tokens.PopExpected(",");
				}
				first = false;

				string expr = "";
				while (tokens.Peek() != ")" && tokens.Peek() != "," && tokens.Peek() != null)
				{
					expr += tokens.Pop();
				}

				if (expr.Length == 0)
				{
					throw new ParserException("cannot have blank expression here.", tokens.PeekToken());
				}

				matchList.Add(expr);
			}

			tokens.PopExpected(")");
			Executable[] trueCode = CodeBlock.Parse(tokens, false);
			Executable[] falseCode = null;
			if (tokens.PopIfPresent("else"))
			{
				falseCode = CodeBlock.Parse(tokens, false);
			}

			return new ArgMatch(matchList, trueCode, falseCode);
		}

		public override void ResolveCode(Class c, Dictionary<object, object> parents)
		{
			foreach (Executable exec in this.TrueCode)
			{
				exec.ResolveCode(c, parents);
			}

			if (this.FalseCode != null)
			{
				foreach (Executable exec in this.FalseCode)
				{
					exec.ResolveCode(c, parents);
				}
			}
		}

		public override void ResolveClassToThis(Class c)
		{
			foreach (Executable ex in this.TrueCode)
			{
				ex.ResolveClassToThis(c);
			}

			if (this.FalseCode != null)
			{
				foreach (Executable ex in this.FalseCode)
				{
					ex.ResolveClassToThis(c);
				}
			}
		}
	}
}
